<template>
  <el-dialog
    :title="dialogTitle"
    :visible.sync="visible"
    width="40%"
    top="10vh"
    :before-close="closeHandle"
    :close-on-click-modal="false"
    class="menu-save-update"
  >
    <el-form v-loading="dataLoad" :model="menuForm" :rules="menuRules" ref="menuForm" label-width="85px"
             @keyup.enter.native="enterFromHandle">
      <el-form-item label="菜单类型" prop="type">
        <el-radio-group v-model="menuForm.type" @change="typeChangeHandle">
          <el-radio :label="0" border>目录</el-radio>
          <el-radio :label="1" border>页面</el-radio>
          <el-radio :label="2" border>按钮</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="父级菜单" prop="parentId">
        <tree-select :data-obj="menuForm" prop-key="parentId" node-key="menuId" :tree-data="menuTreeData"
                     @node-click="menuParentChangeHandle" />
      </el-form-item>
      <el-form-item label="菜单名称" prop="name">
        <el-input v-model="menuForm.name" placeholder="请输入菜单名称"></el-input>
      </el-form-item>
      <el-form-item label="菜单路径" prop="path">
        <el-input v-model="menuForm.path" :disabled="!pageMenu" placeholder="请输入菜单路径"></el-input>
      </el-form-item>
      <div class="menu-from">
        <div class="m-permit">
          <el-form-item label="权限标识" prop="permit">
            <el-input v-model="menuForm.permit" :disabled="!buttonMenu" placeholder="请输入权限标识"></el-input>
          </el-form-item>
        </div>
        <div class="m-tips">
          <el-tooltip placement="bottom" effect="light" class="warning-icon">
            <div slot="content">
              可以输入多个权限标识，以逗号分割，如：
              <br>
              user-add,menu-list,role-update
            </div>
            <i class="el-icon-warning"></i>
          </el-tooltip>
        </div>
      </div>
      <el-form-item label="菜单图标" prop="icon">
        <el-popover
          placement="bottom-start"
          width="460"
          trigger="click"
          @show="$refs.iconSelect.reset()"
        >
          <IconSelect ref="iconSelect" @selected="menuIconChangeHandle" />
          <el-input slot="reference" v-model="menuForm.icon" :disabled="buttonMenu" readonly placeholder="点击选择菜单图标">
            <svg-icon v-if="menuForm.icon" slot="prefix"
              :icon-class="menuForm.icon"
              style="height: 32px;width: 16px;"
            />
            <i v-else slot="prefix" class="el-icon-search el-input__icon" />
          </el-input>
        </el-popover>
      </el-form-item>
      <div class="menu-from">
        <div class="m-sort">
          <el-form-item label="排序等级" prop="sort">
            <el-input v-model.number="menuForm.sort" maxlength="5" placeholder="请输入排序等级"></el-input>
          </el-form-item>
        </div>
        <div class="m-display">
          <el-form-item label="显示状态" prop="display">
            <el-radio-group v-model="menuForm.display" :disabled="buttonMenu">
              <el-radio :label="0" border>显示</el-radio>
              <el-radio :label="1" border>隐藏</el-radio>
            </el-radio-group>
          </el-form-item>
        </div>
      </div>
    </el-form>

    <span slot="footer">
      <el-button @click="closeHandle(false)">取 消</el-button>
      <el-button v-show="!optType" :disabled="loading" type="primary" @click="saveMenuHandle">添加</el-button>
      <el-button v-show="optType" :disabled="loading" type="primary"  @click="updateMenuHandle">修改</el-button>
    </span>
  </el-dialog>
</template>

<script>
  // 树形选择插件
  // import TreeSelect from '@riophae/vue-treeselect'
  import TreeSelect from '@/components/common/tree-select'
  // 树形插件样式
  // import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  // 图标选择插件
  import IconSelect from '@/components/common/icon-select/index.vue'

  /**
   * 系统菜单添加或修改插件
   */
  export default {
    name: "menu-save-update-dialog",
    components: { TreeSelect, IconSelect },
    data() {
      let checkMenuPath = (rule, value, callback) => {
        // 菜单类型为‘菜单’才进行校验
        if (this.menuForm.type !== 1 || value !== '') {
          return callback()
        }
        callback(new Error('菜单路径不能为空'))
      }
      let checkMenuPerms = (rule, value, callback) => {
        // 菜单类型为‘按钮’才进行校验
        if (this.menuForm.type !== 2 || value !== '') {
          return callback()
        }
        callback(new Error('权限标识不能为空'))
      }
      let checkMenuIcon = (rule, value, callback) => {
        // 菜单类型为’目录‘或‘路由菜单’才进行校验
        if (this.buttonMenu || value !== '') {
          return callback()
        }
        callback(new Error('菜单图标不能为空'))
      }
      return {
        // 弹出框显示状态[true-显示 false-隐藏]
        visible: false,
        // 弹出框标题
        dialogTitle: undefined,
        // 菜单添加或修改[false-添加 true-修改]
        optType: false,
        // 菜单表单对象
        menuForm: {
          // 菜单主键
          menuId: undefined,
          // 父级菜单主键
          parentId: undefined,
          // 父级菜单路径
          menuPath: undefined,
          // 菜单名字
          name: '',
          // 菜单路径
          path: '',
          // 菜单权限标识
          permit: '',
          // 菜单类型
          type: 0,
          // 菜单图标
          icon: '',
          // 菜单排序等级
          sort: '',
          // 菜单是否显示
          display: 0,
          // 菜单关联部门主键数据
          deptIds: undefined
        },
        // 数据是否加载[false-不加载 true-加载]
        dataLoad: false,
        // 按钮是否可被点击[false-可以被点击 true-不可被点击]
        buttonLoad: false,
        // 菜单选择树形结构数组数据
        menuTreeData: [],
        // 菜单树选中节点对象（用于表单提交时校验操作）
        menuTreeNode: {},
        // 菜单表单校验规则
        menuRules: {
          parentId: [
            { required: true, message: '父级菜单不能为空', trigger: 'blur' }
          ],
          name: [
            { required: true, message: '菜单名称不能为空', trigger: 'blur' }
          ],
          path: [
            { required: true, validator: checkMenuPath, trigger: 'blur' },
          ],
          permit: [
            { required: true, validator: checkMenuPerms, trigger: 'blur' },
          ],
          icon: [
            { required: true, validator: checkMenuIcon, trigger: 'change' },
          ],
          sort: [
            { required: true, message: '排序等级不能为空', trigger: 'blur' },
            { type: 'number', message: '排序等级必须为数字值'}
          ],
        }
      }
    },
    computed: {
      // 页面菜单
      pageMenu() {
        return this.menuForm.type === 1
      },
      // 按钮菜单
      buttonMenu() {
        return this.menuForm.type === 2
      },
      // 加载状态
      loading() {
        return this.dataLoad || this.buttonLoad;
      }
    },
    methods: {
      /**
       * 初始化菜单弹出框事件
       * @param {Object}  menu     菜单对象（添加菜单时，默认为上级菜单，修改菜单时，菜单参数对象为当前菜单）
       * @param {boolean} optType  操作类型[false-添加 true-修改]
       * @param {number}  menuType 菜单类型（只有添加菜单时才有值，默认为添加菜单的菜单类型）
       */
      initMenuDialog(menu, optType, menuType) {
        // 打开弹出框
        this.visible = true;
        this.optType = optType
        this.dialogTitle = optType ? '修改菜单' : '添加菜单'

        // 初始化父级菜单树
        this.initMenuTreeSelect(menu, optType)

        if (optType) {
          /*
            修改菜单
           */
          let menuForm = this.menuForm;
          menuForm.menuId = menu.menuId;
          menuForm.parentId = menu.parentId;
          menuForm.menuPath = menu.menuPath;
          menuForm.name = menu.name;
          menuForm.path = menu.path;
          menuForm.permit = menu.permit;
          menuForm.type = menu.type;
          menuForm.icon = menu.icon;
          menuForm.sort = menu.sort;
          menuForm.display = menu.display;
        } else {
          /*
            添加菜单
           */
          // 设置菜单类型
          this.menuForm.type = menuType
          if (menuType === 2) {
            // 如果新增菜单类型是’按钮‘，则显示状态为’隐藏‘
            this.menuForm.display = 1;
          }
          // 初始化排序等级
          this.getNextSort(menu);
        }
      },
      /**
       * 获取子菜单的下一个排序等级
       * @param {Object} menu 菜单对象（传入参数对象为空时，使用默认参数）
       */
      getNextSort(menu = {}) {
        this.$axios.$get('/sys/menu/next/sort', { params: { menuId: menu.menuId }})
          .then(({ data }) => {
            this.menuForm.sort = data;
          })
          .catch(() => {})
      },
      /**
       * 初始化父级菜单选择树事件
       * @param {Object}  menu    父级菜单对象（）
       * @param {boolean} optType 操作类型[false-添加 true-修改]
       */
      initMenuTreeSelect(menu, optType) {
        // 按钮不可被点击
        this.dataLoad = true;
        this.$axios.$get('/sys/menu/tree', { params: { menuId: optType ? menu.menuId : undefined }})
          .then(({ data:menuTree }) => {
            // 添加顶层菜单
            this.menuTreeData.push(menuTree)

            if (!optType) {
              // 新增菜单
              let menuForm = this.menuForm;
              if (!!menu) {
                // 设置默认父级菜单
                menuForm.parentId = menu.menuId;
                menuForm.menuPath = menu.menuPath;
              } else {
                // 设置默认父级菜单和父级菜单路径
                menuForm.parentId = menuTree.menuId;
                menuForm.menuPath = menuTree.menuPath;
              }
            }
          })
          .catch(() => {})
          .finally(() => {
            // 按钮恢复可点击
            this.dataLoad = false;
          })
      },
      // 表单回车事件
      enterFromHandle() {
        if (this.optType) {
          this.updateMenuHandle()
        } else {
          this.saveMenuHandle()
        }
      },
      // 添加菜单事件
      saveMenuHandle() {
        this.$refs.menuForm.validate((valid) => {
          if (!valid) {
            return false
          }
          let menuForm = this.menuForm;
          if (this.menuTreeNode.type === 1 && !this.buttonMenu) {
            this.notify('', '温馨提示', '路由菜单下只能包含按钮菜单，请确认')
            return false;
          }
          // 按钮不可被点击
          this.buttonLoad = true

          // console.log(this.menuForm, 'this.menuForm');
          this.$axios.$post('/sys/menu/save', menuForm)
            .then(() => {
              this.notify('success', '保存成功', `成功添加'${menuForm.name}'${menuForm.type === 0 ? '目录' : menuForm.type === 1 ? '路由' : '按钮'}菜单`)
              // 关闭弹出框
              this.closeHandle(true)
            })
            .catch(() => {})
            .finally(() => {
              // 按钮恢复可点击
              this.buttonLoad = false
            })
        });

      },
      // 修改菜单事件
      updateMenuHandle() {
        this.$refs.menuForm.validate((valid) => {
          if (!valid) {
            return
          }
          let menuForm = this.menuForm;
          if (this.menuTreeNode.type === 1 && !this.buttonMenu) {
            this.notify('', '温馨提示', '路由菜单下只能包含按钮菜单，请确认。')
            return false
          }
          // 按钮不可被点击
          this.buttonLoad = true

          this.$axios.$post('/sys/menu/update', menuForm)
            .then(() => {
              this.notify('success', '操作成功', `成功修改'${menuForm.name}'${menuForm.type === 0 ? '目录' : menuForm.type === 1 ? '路由' : '按钮'}菜单`);

              this.closeHandle(true)
            })
            .catch(() => {})
            .finally(() => {
              // 按钮恢复可点击
              this.buttonLoad = false
            })
        })
      },
      /**
       * 菜单类型值切换事件
       * @param {number} type 最新类型
       */
      typeChangeHandle(type) {
        let menuForm = this.menuForm;
        if (type === 0) {
          // 目录菜单
          menuForm.path = ''
          menuForm.permit = '';
          menuForm.display = 0;
        } else if (type === 1) {
          // 页面菜单
          menuForm.permit = '';
          menuForm.display = 0;
        } else {
          // 按钮菜单
          menuForm.path = '';
          menuForm.icon = '';
          menuForm.display = 1;
        }
        this.$refs.menuForm.clearValidate(['path', 'permit', 'icon'])
      },
      // 弹出框关闭处理事件
      closeHandle(bool) {
        // 关闭弹出框
        this.visible = false;
        // 重置菜单表单对象
        this.$refs.menuForm.resetFields();
        // 手动清空菜单id
        this.menuForm.menuId = undefined
        this.menuForm.parentId = undefined
        // 手动清空父级菜单路径
        this.menuForm.menuPath = undefined
        // 清空菜单树数据
        this.menuTreeData = []
        // 手动菜单树选中节点对象
        this.menuTreeNode = {}

        if (typeof bool === 'function') {
          bool = false
        }
        // 向上传递事件
        this.$emit('close-dialog', bool)
      },
      // 菜单图标选择事件
      menuIconChangeHandle(iconName) {
        if (!this.buttonMenu) {
          this.menuForm.icon = iconName
        }
      },
      /**
       * 菜单树选择项发生改变事件
       * @param {Object} node 菜单选择树选中节点
       */
      menuParentChangeHandle(node) {
        // console.log('menuNode', node);
        // 更换菜单选择树选中的节点
        this.menuTreeNode = node
        let menuForm = this.menuForm;
        // 设置父级菜单主键和父级菜单路径
        menuForm.parentId = node.menuId;
        menuForm.menuPath = node.menuPath;
        /*
          1、如果选中的节点时顶级目录，弹出框菜单类型自动变成‘目录’菜单
          2、如果选中的节点时目录菜单节点，弹出框菜单类型自动变成‘菜单’菜单
          3、如果选中的节点是路由菜单节点，弹出框菜单类型自动变成‘按钮‘菜单
         */
        menuForm.type = node.type + 1;
        if (menuForm.type === 0) {
          // 目录菜单
          menuForm.path = ''
          menuForm.permit = '';
          menuForm.display = 0;
        } else if (menuForm.type === 1) {
          // 页面菜单
          menuForm.permit = '';
          menuForm.display = 0;
        } else {
          // 按钮菜单
          menuForm.path = '';
          menuForm.icon = '';
          menuForm.display = 1;
        }
        // 重新获取下一个默认排序等级
        this.getNextSort(node);
        // 清空校验
        this.$refs.menuForm.clearValidate(['parentId', 'path', 'permit', 'icon'])
      }
    },
  }
</script>

<!--
  css字符对应
  m -> menu
-->
<style scoped>
  .menu-save-update >>> .el-dialog__body {
    padding: 20px;
  }
  .menu-from {
    position: relative;
    box-sizing: border-box;
  }
  .menu-from:before, .menu-from:after {
    display: table;
    content: "";
  }
  .menu-from:after {
    clear: both;
  }
  .menu-from .m-sort, .menu-from .m-display, .menu-from .m-display {
    width: 50%;
    float: left;
    box-sizing: border-box;
  }
  .menu-from .m-permit {
    width: 90%;
    float: left;
    box-sizing: border-box;
  }
  .menu-from .m-tips {
    width: 10%;
    float: left;
    box-sizing: border-box;
  }
  .m-tips .warning-icon {
    margin-left: 15px;
    margin-top: 8px;
    font-size: 20px;
    text-align: center;
    color: #e6a23c;
    cursor: pointer;
  }
</style>
